/*
 *    Copyright (c) 2018-2025, lengleng All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * Neither the name of the pig4cloud.com developer nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * Author: lengleng (wangiegie@gmail.com)
 */

package com.pig4cloud.pigx.user.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pig4cloud.pigx.common.core.constant.SecurityConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.customize.i18n.util.MessageUtils;
import com.pig4cloud.pigx.common.customize.utils.id.IdWorker;
import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.common.log.annotation.UserLog;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.user.api.feign.RippleRemoteGatewayService;
import com.pig4cloud.pigx.user.api.feign.RippleRemoteUpmsService;
import com.pig4cloud.pigx.user.api.feign.RippleRemoteWalletService;
import com.pig4cloud.pigx.user.constant.RedisMessageType;
import com.pig4cloud.pigx.user.dto.UserMobileDTO;
import com.pig4cloud.pigx.user.entity.User;
import com.pig4cloud.pigx.user.mapstruct.UserMobileStruct;
import com.pig4cloud.pigx.user.service.UserService;
import com.pig4cloud.pigx.user.util.StringRandom;
import com.pig4cloud.pigx.user.vo.UserMobileVO;
import com.pig4cloud.pigx.user.vo.UserPageApiKeyVO;
import io.seata.spring.annotation.GlobalTransactional;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.pig4cloud.pigx.user.constant.I18nMessages.CHANGE_FAILURE;
import static com.pig4cloud.pigx.user.constant.I18nMessages.INVALID_INVITATION_CODE;
import static com.pig4cloud.pigx.user.constant.I18nMessages.MODIFY_SUCCESSFULLY;
import static com.pig4cloud.pigx.user.constant.I18nMessages.SYSTEM_USER_CANNOT_BE_DELETED;

/**
 * 平台用户
 *
 * @author pigx code generator
 * @date 2022-08-08 15:07:46
 */
@RestController
@RequiredArgsConstructor
@RequestMapping("/user")
@Api(value = "user", tags = "平台用户管理")
public class UserController {

    /**
     * 系统用户id，无法删除
     */
    private static final List<Long> SYSTEM_USER_ID =
            Arrays.asList(
                    1000L, 2000L, 3000L, 4000L, 5000L,
                    6000L, 7000L, 8000L, 9000L, 10000L);

    /**
     * 平台用户
     */
    private final UserService userService;
    /**
     * RedisKeyEnum
     */
    private final StringRedisTemplate stringRedisTemplate;
    /**
     * 雪花id
     */
    private final IdWorker idWorker;
    /**
     * pigx-gateway的Feign
     */
    private final RippleRemoteGatewayService rippleRemoteGatewayService;
    /**
     * pigx-upms的Feign
     */
    private final RippleRemoteUpmsService rippleRemoteUpmsService;
    /**
     * ripple-wallet-biz的Feign
     */
    private final RippleRemoteWalletService remoteWalletService;

    /**
     * 分页查询
     *
     * @param page 分页对象
     * @param user 平台用户
     * @return
     */
    @ApiOperation(value = "分页查询", notes = "分页查询")
    @GetMapping("/page")
    @PreAuthorize("@pms.hasPermission('user_user_view')")
    public R getUserPage(Page page, User user) {
        return R.ok(userService.page(page, new LambdaQueryWrapper<User>()
                .eq(!StringUtils.isEmpty(user.getAddress()), User::getAddress, user.getAddress())
                .eq(user.getInviterId() != null, User::getInviterId, user.getInviterId())
                .eq(!StringUtils.isEmpty(user.getChain()), User::getChain, user.getChain())
                .eq(user.getIsBroker() != null, User::getIsBroker, user.getIsBroker())
                .ge(user.getStartTime() != null, User::getCreateTime, user.getStartTime())
                .le(user.getEndTime() != null, User::getCreateTime, user.getEndTime())
                .like(user.getUid() != null, User::getUid, user.getUid())
                .like(user.getEmail() != null && !user.getEmail().isEmpty(), User::getEmail, user.getEmail())
                .orderByDesc(User::getCreateTime)));
    }


    /**
     * 通过id查询平台用户
     *
     * @param id id
     * @return R
     */
    @ApiOperation(value = "通过id查询", notes = "通过id查询")
    @GetMapping("/{id}")
    @PreAuthorize("@pms.hasPermission('user_user_view')")
    public R getById(@PathVariable("id") Long id) {
        return R.ok(userService.getById(id));
    }

    /**
     * 新增平台用户
     *
     * @param user 平台用户
     * @return R
     */
    @ApiOperation(value = "新增平台用户", notes = "新增平台用户, " +
            "@RequestBody：email, *chain, *address, moneyPassword, inviteCode, inviterId, *status")
    @SysLog("新增平台用户")
    @PostMapping
    @PreAuthorize("@pms.hasPermission('user_user_add')")
    @GlobalTransactional(rollbackFor = Throwable.class)
    public R save(@RequestBody User user) {

        if (user.getInviterId() != null) {
            User inviter = userService.getOne(new QueryWrapper<User>().eq("uid", user.getInviterId()));
            if (inviter == null) {
                return R.failed(MessageUtils.get(INVALID_INVITATION_CODE));
            }
        }
        //雪花id
        user.setUid(idWorker.nextId());
        //创建时间
        user.setCreateTime(LocalDateTime.now());
        //经纪人
        user.setIsBroker(0);
        //是否确认风险告知 0否 1是
        user.setIsConfrimRisk(0);
        //用户语言设置
        user.setLanguageCode("zh_CN");
        boolean b = userService.save(user);
        //钱包模块 注册的用户
        remoteWalletService.create(user.getUid(), SecurityConstants.FROM_IN);
        return R.ok(b);
    }

    /**
     * 修改平台用户
     *
     * @param user 平台用户
     * @return R
     */
    @ApiOperation(value = "修改平台用户", notes = "修改平台用户")
    @SysLog("修改平台用户")
    @PutMapping
    @PreAuthorize("@pms.hasPermission('user_user_edit')")
    public R updateById(@RequestBody User user) {
        user.setUpdateTime(LocalDateTime.now());
        boolean b = userService.updateById(user);
        return R.ok(b);
    }

    /**
     * 通过id删除平台用户
     *
     * @param id id
     * @return R
     */
    @ApiOperation(value = "通过id删除平台用户", notes = "通过id删除平台用户")
    @SysLog("通过id删除平台用户")
    @DeleteMapping("/{id}")
    @PreAuthorize("@pms.hasPermission('user_user_del')")
    @GlobalTransactional(rollbackFor = Throwable.class)
    public R removeById(@PathVariable Long id) {
        //系统用户无法删除
        if (SYSTEM_USER_ID.contains(id)) {
            return R.failed(MessageUtils.get(SYSTEM_USER_CANNOT_BE_DELETED));
        }
        // 冻结账户经纪人
        User user = new User();
        user.setId(id);
        user.setIsBroker(0);
        userService.updateAgentById(user);

        return R.ok(userService.removeById(id));
    }


    /**
     * 导出excel 表格
     *
     * @param user 查询条件
     * @return excel 文件流
     */
    @ResponseExcel
    @GetMapping("/export")
    @PreAuthorize("@pms.hasPermission('user_user_export')")
    public List<User> export(User user) {
        return userService.list(Wrappers.query(user));
    }

    /**
     * 用户注册
     *
     * @param userDTO
     * @return
     */
    @ApiOperation(value = "用户邮箱注册", notes = "用户邮箱注册，@RequestBody：" +
            "email、userVerificationCode（邮箱验证码）、chain（公链）、address、invitation、moneyPassword")
    @Inner(value = false)
    @PostMapping("/userRegister")
    @GlobalTransactional(rollbackFor = Throwable.class)
    public R userRegister(@RequestBody UserMobileDTO userDTO) {
        return userService.userRegister(userDTO);

    }

    /**
     * 获取用户签名字符串
     *
     * @return
     */
    @Inner(value = false)
    @ApiOperation(value = "获取用户签名字符串", notes = "获取用户签名字符串，@RequestBody：address(钱包地址)")
    @PostMapping("/getAddressMassage")
    public R getAddressMassage(@RequestBody User user) {
        String massage = StringRandom.getLowercaseStringRandom(16);
        stringRedisTemplate.opsForValue().set(
                user.getAddress() + " massage = " + RedisMessageType.Customer_Address_Message,
                massage, 60 * 3, TimeUnit.SECONDS);
        return R.ok(massage);
    }

    /**
     * 密码解密后请求pigx-gateway中
     *
     * @param header
     * @param userMobileDTO
     * @return
     */
    @Inner(value = false)
    @ApiOperation(value = "用户签名验证", notes = "用户签名验证 @RequestBody address、 Return：userIsExist（用户是否注册 false=未注册 true=已注册）、userInfo")
    @PostMapping("/login")
    @GlobalTransactional(rollbackFor = Throwable.class)
    public R login(@RequestHeader HttpHeaders header, @RequestBody UserMobileDTO userMobileDTO) {
        return userService.login(header, userMobileDTO);
    }

    /**
     * 用户修改邮箱
     */
    @UserLog("#user.chain 客户修改邮箱")
    @ApiOperation(value = "用户修改邮箱", notes = "用户修改邮箱， @RequestBody：uid、email、userVerificationCode（邮箱验证码）")
    @PostMapping("/modifyEmail")
    @Transactional(rollbackFor = Throwable.class)
    public R modifyEmail(@RequestBody UserMobileDTO user) {
        return userService.modifyEmail(user);
    }

    /**
     * 用户修改交易密码
     */
    @UserLog("客户修改交易密码")
    @ApiOperation(value = "用户修改交易密码", notes = "用户修改交易密码，@RequestBody：uid、email、userVerificationCode（邮箱验证码）、newMoneyPassword（新密码）")
    @PostMapping("/modifyMoneyPassword")
    @Transactional(rollbackFor = Throwable.class)
    public R modifyMoneyPassword(@RequestBody UserMobileDTO user) {
        return userService.modifyMoneyPassword(user);
    }

    /**
     * 根据钱包地址获取用户信息
     *
     * @param address
     * @return
     */
    @ApiOperation(value = "根据钱包地址获取用户信息", notes = "根据钱包地址获取用户信息，@RequestParam：address")
    @GetMapping("/getUserByAddress")
    public R getUserByAddress(@RequestParam("address") String address) {
        User user = userService.getOne(new QueryWrapper<User>()
                .select("id", "email", "address", "chain", "uid", "is_confrim_risk", "language_code", "invite_code")
                .eq("address", address));
        UserMobileVO userMobileVO = UserMobileStruct.INSTANCE.user2Vo(user);
        return R.ok(userMobileVO);
    }

    /**
     * 客户确认风险告知
     *
     * @param userMobileDTO 平台用户
     * @return R
     */
    @ApiOperation(value = "客户确认风险告知", notes = "客户确认风险告知, @RequestBody: uid")
    @PutMapping("/confirmationRisk")
    public R confirmationRisk(@RequestBody UserMobileDTO userMobileDTO) {
        User user = UserMobileStruct.INSTANCE.dto2user(userMobileDTO);

        User updateUser = new User();
        updateUser.setIsConfrimRisk(1);
        boolean b = userService.update(updateUser, new QueryWrapper<User>().eq("uid", user.getUid()));
        if (b) {
            return R.ok(MessageUtils.get(MODIFY_SUCCESSFULLY));
        }
        return R.failed(MessageUtils.get(CHANGE_FAILURE));
    }

    /**
     * 修改用户语言
     *
     * @param user
     * @return
     */
    @ApiOperation(value = "修改用户语言", notes = "修改用户语言, @RequestBody uid, languageCode（语言编号）")
    @PostMapping("/modifyingUserLanguage")
    @Transactional(rollbackFor = Throwable.class)
    public R modifyingUserLanguage(@RequestBody UserMobileDTO user) {
        return userService.modifyingUserLanguage(user);

    }

    /**
     * 修改平台用户经纪人状态
     *
     * @param user 平台用户
     * @return R
     */
    @ApiOperation(value = "修改平台用户经纪人状态", notes = "修改平台用户经纪人状态, @RequestBody:" +
            "id, isBroker, userName, password")
    @SysLog("修改平台用户经纪人状态")
    @PutMapping("/updateAgentById")
    @GlobalTransactional(rollbackFor = Throwable.class)
    public R updateAgentById(@RequestBody User user) {
        return userService.updateAgentById(user);
    }

    /**
     * 修改平台用户状态
     *
     * @param user 平台用户
     * @return R
     */
    @ApiOperation(value = "修改平台用户状态", notes = "修改平台用户状态, @RequestBody:" +
            "id, status")
    @PutMapping("/updateStatusById")
    @Transactional(rollbackFor = Throwable.class)
    public R updateStatusById(@RequestBody User user) {

        user.setUpdateTime(LocalDateTime.now());
        return userService.updateStatusById(user);
    }

    /**
     * 查询拥有apiKey的用户
     *
     * @param page      分页参数
     * @param condition 查询条件
     * @return {@link R< Page< UserPageApiKeyVO>>}
     * @since 2022/10/28 16:18
     */
    @ApiOperation(value = "查询拥有apiKey的用户", notes = "查询拥有apiKey的用户")
    // @PreAuthorize("@pms.hasPermission('user_user_api_key_view')")
    @GetMapping("/page/api-key")
    public R<Page<UserPageApiKeyVO>> pageApiKey(Page<User> page, UserPageApiKeyVO condition) {
        return R.ok(userService.pageApiKey(page, condition));
    }
}
